﻿
#include "EWindow.h"
#include "Windowsx.h"
#include "EGraphics.h"
#include "EInputListener.h"
#include "ECanvas.h"
#include <ctime>

namespace Base3D
{
	//--------------------------------------------------------------------------

	EGameWindow	*EGameWindow::GWindow;

	//--------------------------------------------------------------------------

	LRESULT EGameWindow::WinProc(HWND hWnd, UINT Msg,WPARAM wParam,LPARAM lParam)
	{
		if (!EGameWindow::GWindow)
			return DefWindowProc(hWnd, Msg, wParam, lParam);

		switch(Msg)
		{
			// 绘制
			case WM_MOVING:
			case WM_PAINT:
			{
				PAINTSTRUCT  ps;
				HDC hdc = BeginPaint(hWnd, &ps);
				//
				EGameWindow::GWindow->onPaint(hdc);
				EndPaint(hWnd, &ps);
				break;
			}
			case WM_TIMER:
			{
				EGameWindow::GWindow->updateWindow();
				break;
			}
			// 键盘按下
			case WM_KEYDOWN:
			{
				EGameWindow::GWindow->onKeyDown(wParam);
				break;
			}
			// 键盘释放
			case WM_KEYUP:
			{
				EGameWindow::GWindow->onKeyRelease(wParam);
				break;
			}
			case WM_MOUSEWHEEL:
			{
				EShort delta = GET_WHEEL_DELTA_WPARAM(wParam); // wheel rotation
				EGameWindow::GWindow->onMouseWheel(delta * 0.5f / PI);
			}

			// 鼠标移动
			case WM_MOUSEMOVE:
			{
				EInt x = GET_X_LPARAM(lParam); 
				EInt y = GET_Y_LPARAM(lParam); 
				EGameWindow::GWindow->onMouseMove(x, y);
				break;
			}
			// 关闭窗口
			case WM_CLOSE:
			{
				DestroyWindow(hWnd);
				break;
			}
			case WM_DESTROY:
			{
				PostQuitMessage(0);
				break;
			}
			default:
				return DefWindowProc(hWnd, Msg, wParam, lParam);
		}
		return 0;
	}

	//--------------------------------------------------------------------------

	EGameWindow::EGameWindow(const EString& windowTitle, HINSTANCE hInstance) : 
	mWindowTitle(windowTitle), mHinstance(hInstance), mCanvasListener(nullptr), mQuite(false)
	{
	    //
		if (!(registerWindow() && createWindow()))
		{
			throw "Init Window Failed!";
		}				
	}

	//--------------------------------------------------------------------------

	EGameWindow::~EGameWindow()
	{
		DestroyWindow(mHwnd);
		for (auto & mInputListener : mInputListeners){
			SafeDelete(mInputListener);
		}

		SafeDelete(mCanvasListener);
	}

	//--------------------------------------------------------------------------

	// 显示窗口
	void EGameWindow::showWindow(EBool show)
	{
		::ShowWindow(mHwnd, SW_SHOW);
		::UpdateWindow(mHwnd);
	}

	//--------------------------------------------------------------------------

	void EGameWindow::updateWindow()
	{
		// 刷心窗口
		::InvalidateRect (mHwnd, nullptr, FALSE) ;
		::UpdateWindow(mHwnd);
	}

	//--------------------------------------------------------------------------

	void EGameWindow::setCanvasListener(ECanvas *canvasListener){
		mCanvasListener = canvasListener;
	}

	//--------------------------------------------------------------------------

	void EGameWindow::onUpdate()
	{
		//if (mCanvasListener)
		//{
		//	EGraphics::clearBuffer(EColor(0, 0, 0));
		//	mCanvasListener->render();
		//	mCanvasListener->onPaint();
		//}
	}

	// 窗口绘制函数
	void EGameWindow::onPaint(HDC hdc)
	{
		if (mCanvasListener)
		{
		    //
			EGraphics::clearBuffer(EColor(0, 0, 0));
			//game render
			mCanvasListener->update();
			mCanvasListener->onPaint();
			//update to screen
			//
			//EGraphics::GBufferedHDC
			EGraphics::fillBuffer(hdc);
		}
	}

	//--------------------------------------------------------------------------

	void EGameWindow::addInputListener(EInputListener* listener){
		mInputListeners.push_back(listener);
	}

	//--------------------------------------------------------------------------

	void EGameWindow::removeInputListener(EInputListener* listener)
	{
		for (auto itr = mInputListeners.begin(); itr != mInputListeners.end();){
			if (*itr == listener){
				mInputListeners.erase(itr++);
			}
			else
				++itr;
		}
	}

	//--------------------------------------------------------------------------

	void EGameWindow::onKeyDown(EInt msg)
	{
		//::MessageBox(0, "Window onKeyDown", 0, 0);
		for(auto & mInputListener : mInputListeners)
			mInputListener->keyPress(msg);
	}

	//--------------------------------------------------------------------------

	void EGameWindow::onKeyRelease(EInt msg)
	{
		//::MessageBox(0, "Window onKeyRelease", 0, 0);
		for(auto & mInputListener : mInputListeners)
			mInputListener->keyRelease(msg);
	}

	//--------------------------------------------------------------------------

	void EGameWindow::onMousePress(bool rightPress){
		if (rightPress)
			::MessageBox(nullptr, "Window R onMousePress", nullptr, 0);
		else
			::MessageBox(nullptr, "Window L onMousePress", nullptr, 0);
	}

	//--------------------------------------------------------------------------

	void EGameWindow::onMouseMove(EInt x, EInt y){
		//::MessageBox(0, "Window onMouseMove", 0, 0);
		for(auto & mInputListener : mInputListeners)
			mInputListener->mouseMove(x, y);
	}

	//--------------------------------------------------------------------------

	void EGameWindow::onMouseWheel(EInt delta){
		for(auto & mInputListener : mInputListeners)
			mInputListener->mouseWheel(delta);
	}

	void EGameWindow::quiteApplication(){
		mQuite = true;
	}

	//--------------------------------------------------------------------------

	void EGameWindow::startLoop()
	{
		//MSG msg;
		//while(::GetMessage(&msg, NULL, 0, 0))
		//{
		//	::TranslateMessage(&msg);
		//	::DispatchMessage(&msg);

		//	mCanvasListener->render();
		//}

		MSG msg;
		while (!mQuite)
		{        
			if (::PeekMessage (&msg, nullptr, 0, 0, PM_REMOVE))
			{        
				if (msg.message == WM_QUIT)        
					break ;        
				::TranslateMessage (&msg) ;        
				::DispatchMessage (&msg) ;        

				onUpdate();
			}
			else
				::Sleep(10);
		}     
	}

	//--------------------------------------------------------------------------

	bool EGameWindow::createWindow()
	{
		mHwnd = ::CreateWindow(	"Base3D", mWindowTitle.c_str(),
			// 窗口不可更改大小
			WS_OVERLAPPEDWINDOW & (~WS_MAXIMIZEBOX)& (~WS_THICKFRAME),
			CW_USEDEFAULT, CW_USEDEFAULT, 
			SCREEN_WIDTH, SCREEN_HEIGHT, 
			nullptr, nullptr, mHinstance, nullptr);

		if (!mHwnd)
		{
			::MessageBox(0, "Create Window Failed", 0, 0);
			return false;
		}

		//RECT clientSize = {CW_USEDEFAULT, CW_USEDEFAULT, SCREEN_WIDTH, SCREEN_HEIGHT};
		//AdjustWindowRect(&clientSize, WS_OVERLAPPEDWINDOW & (~WS_MAXIMIZEBOX)& (~WS_THICKFRAME), false);

		::SetTimer(mHwnd, WM_TIMER, 35,nullptr);

		// 手动播种
		srand(time(nullptr));

		return true;
	}

	//--------------------------------------------------------------------------

	bool EGameWindow::registerWindow()
	{
		WNDCLASS wind;
		{
			wind.style			= CS_HREDRAW | CS_VREDRAW;
			wind.lpfnWndProc	= (WNDPROC)EGameWindow::WinProc;
			wind.cbClsExtra		= 0;
			wind.cbWndExtra		= 0;
			wind.hInstance		= mHinstance;
			wind.hIcon			= LoadIcon(nullptr, IDI_APPLICATION);
			wind.hCursor		= LoadCursor(nullptr, IDC_ARROW);
			wind.hbrBackground	= (HBRUSH)GetStockObject(BLACK_BRUSH);
			wind.lpszMenuName	= nullptr;
			wind.lpszClassName	= "Base3D";
		}

		if (!RegisterClass(&wind))
		{
			::MessageBox(nullptr, "Register Class Failed", nullptr, 0);
			return false;
		}

		return true;
	}

	//--------------------------------------------------------------------------
}